﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace DBTool
{
    public partial class CSVReader
    {
        #region Member Variables
        private Dictionary<Key, string> _dic = null;
        private List<string> _rows;
        private List<string> _titles;
        private int _firstColumn;
        private string _fileName;
        private string _fileOriginalText;
        static public string _commaChangeValue_In_QuotationMark = "!Q@W#E";
        #endregion


        #region ctor dtor
        public CSVReader(string file)
        {
            _firstColumn = 0;
            _dic = new Dictionary<Key, string>();

            LoadFile(file);
        }
        #endregion


        #region Member Methods
        private bool LoadFile(string filePath)
        {
            _fileName = Path.GetFileNameWithoutExtension( filePath );
            _fileOriginalText = System.IO.File.ReadAllText(filePath);

            if (true == string.IsNullOrEmpty(_fileOriginalText))
            {
                MessageBox.Show("ReadFile Failed : " + filePath, "LoadFile() Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            Parse(_fileOriginalText);

            return true;
        }

        private void Parse(string text)
        {
            text = text.Replace("\r\n", "\n");

            _rows = ManufactureRows( text.Split('\n') );
            _titles = RemoveNullString( _rows[0].Split(',') );

            for ( int rowCount = 1; rowCount < _rows.Count; ++rowCount )
            {
                string[] rowColumns = _rows[rowCount].Split(',');

                for ( int column = 0; column < _titles.Count; ++column )
                {
                    if ( true == _dic.ContainsKey( new Key( rowCount, _titles[column] ) ) )
                        continue;

                    if( rowColumns.Length <= column )
                    {
                        MessageBox.Show("CSV Title content not Match. Check : " + _fileName , _fileName + " Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        continue;
                    }

                    if ( true == string.IsNullOrEmpty( rowColumns[column] ) )
                    {
                        MessageBox.Show("Values Is Null\n" + "FileName : " + _fileName + "\n_titles[column] : " + _titles[column] + "\n row : " + rowCount
                                        , _fileName + "Cell Value is Null", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    
                    string rowColumnValue = rowColumns[column].Replace( _commaChangeValue_In_QuotationMark, "," );
                    _dic.Add( new Key( rowCount, _titles[column] ), rowColumnValue );
                }
            }
        }

        private List<string> ManufactureRows(string[] rows)
        {
            List<string> returnRows = RemoveNullString(rows);

            returnRows = RemoveUnnecessaryRow(returnRows);

            returnRows = ChangeCommaInQuotationMark(returnRows);

            return returnRows;
        }

        private List<string> RemoveNullString(string[] text)
        {
            List<string> removedNullString = new List<string>();

            foreach (string data in text)
            {
                if (true == string.IsNullOrEmpty(data))
                    continue;

                removedNullString.Add(data);
            }

            return removedNullString;
        }

        private List<string> RemoveUnnecessaryRow(List<string> rows)
        {
            List<string> removeString = new List<string>();

            foreach (string row in rows)
            {
                string[] columns = row.Split(',');

                // None ID Row Remove
                if (true == string.IsNullOrEmpty(columns[_firstColumn]))
                {
                    MessageBox.Show(row, "FirstColumn Is NULL", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //removeString.Add(row);
                }
            }

            foreach (string row in removeString)
            {
                if (false == rows.Contains(row))
                    continue;

                rows.Remove(row);
            }

            return rows;
        }

        private List<string> ChangeCommaInQuotationMark( List<string> rows )
        {
            List<string> returnRows = new List<string>();
            bool quotationMarkStarted = false;

            foreach (string row in rows)
            {
                string newRow = "";

                for (int i = 0; i < row.Length; ++i)
                {
                    if (row[i] == '\"')
                        quotationMarkStarted = quotationMarkStarted == true ? false : true;

                    if (row[i] == ',' && true == quotationMarkStarted)
                        newRow += _commaChangeValue_In_QuotationMark;
                    else
                        newRow += row[i];
                }

                returnRows.Add( newRow );
            }

            return returnRows;
        }

        public int GetRowCount()
        {
            if (null == _rows)
            {
                MessageBox.Show("Table rows is Null Check Table Load", "GetRowCount()", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return 0;
            }

            return _rows.Count;
        }

        public string[] GetColumnTitle()
        {
            if (null == _titles)
            {
                MessageBox.Show("GetTitle Error", "GetColumnTitle()", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }

            return _titles.ToArray();
        }

        public IList<string> GetRows()
        {
            if (null == _rows)
            {
                MessageBox.Show("GetRows Error", "GetRows()", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return null;
            }

            return _rows.AsReadOnly();
        }

        public string Find(int row, string title)
        {
            Key key = new Key(row, title);
            if (false == _dic.ContainsKey(key))
            {
                MessageBox.Show("CSVReader Error Not Contains Key. \n" + _fileName + " row :  " + row + ", title : " + title, "FindError", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return string.Empty;
            }

            return _dic[key];
        }

        public bool Compare(CSVReader compareText)
        {
            int compareResult = _fileOriginalText.CompareTo( compareText._fileOriginalText );
            return compareResult == 0 ? true : false;
        }
        #endregion
    }


    public partial class CSVReader
    {
        #region csv key structure
        private class Key
        {
            public int row
            {
                get;
                set;
            }
            public string title
            {
                get;
                set;
            }

            public Key(int row, string title)
            {
                this.row = row;
                this.title = title;
            }

            public override bool Equals(System.Object obj)
            {
                if (null == obj)
                    return false;

                Key key = obj as Key;
                if (null == key)
                    return false;

                return (key.row == row) && (key.title == title);
            }

            public bool Equals(Key key)
            {
                if (null == key)
                    return false;

                return (key.row == row) && (key.title == title);
            }

            public override int GetHashCode()
            {
                return row ^ title.GetHashCode();
            }

            public override string ToString()
            {
                return "Key{row=" + row + ", title=" + title + "}";
            }

            public static bool operator ==(Key a, Key b)
            {
                if (System.Object.ReferenceEquals(a, b))
                    return true;

                if (((object)a == null) || ((object)b == null))
                    return false;

                return a.row == b.row && a.title == b.title;
            }

            public static bool operator !=(Key a, Key b)
            {
                return !(a == b);
            }
        }
        #endregion
    }

}
